package com.hxh.generater.springBoot;

import com.alibaba.fastjson.JSONArray;
import com.hxh.entity.Project;
import com.hxh.entity.TemplateConfig;
import com.hxh.entity.po.ClassInfo;
import com.hxh.service.TemplateConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @ProjectName: AICode
 * @Package: com.hxh.generater
 * @ClassName: GenerationController
 * @Author: HXH
 * @Description: 通过读取模板, 自动生成代码的类，屏蔽不同模板之间的差异，统一调用
 * @Date: 2023/11/28 15:08
 */
@Slf4j
@Component
public class GenerationSpringBootAdapter {
    @Autowired
    TemplateConfigService templateConfigService;

    /**
     * 生成controller的入口方法名称，下同
     */
    private static final String GENERATION_CONTROLLER_METHOD = "generationControllerClass";
    private static final String GENERATION_SERVICE_METHOD = "generationServiceClass";
    private static final String GENERATION_SERVICE_IMPL_METHOD = "generationServiceImplClass";
    private static final String GENERATION_DAO_METHOD = "generationDaoClass";
    private static final String GENERATION_MAPPER_METHOD = "generationMapper";
    private static final String GENERATION_ENTITY_METHOD = "generationEntity";
    private static final String GENERATION_ENTITY_MAPPING_METHOD = "generationEntityMappingClass";
    /**
     * 初始化核心代码入口方法名称
     */
    private static final String INIT_CORE = "initCore";
    /**
     * 初始化菜单入口方法名称
     */
    private static final String INIT_TABLE_MENU = "initTableMenu";
    /**
     * 生成crud工具代码，用于预览代码的入口方法名称
     */
    private static final String PROCESS = "process";

    /**
     * @param project:
     * @param classInfo:
     * @return void
     * @author HXH
     * @description: 根据模板, 在项目中生成controller代码
     * @date 2024/5/22
     **/
    public void generationControllerClass(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationControllerMethod = crudObject.getClass().getDeclaredMethod(GENERATION_CONTROLLER_METHOD, Project.class, ClassInfo.class);
        generationControllerMethod.invoke(crudObject, project, classInfo);
    }

    /**
     * @param project   项目信息
     * @param classInfo
     * @throws Exception
     * @author HXH
     * @description: 生成service代码
     * @date 2024/8/15
     */
    public void generationServiceClass(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationServiceMethod = crudObject.getClass().getDeclaredMethod(GENERATION_SERVICE_METHOD, Project.class, ClassInfo.class);
        generationServiceMethod.invoke(crudObject, project, classInfo);
    }

    /**
     * @Author: hxh
     * @Description: 生成serviceImpl代码
     * @DateTime: 2024/8/15 10:34
     * @Param: project
     * @Param: classInfo
     * @Return void
     */
    public void generationServiceImplClass(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationServiceMethod = crudObject.getClass().getDeclaredMethod(GENERATION_SERVICE_IMPL_METHOD, Project.class, ClassInfo.class);
        generationServiceMethod.invoke(crudObject, project, classInfo);
    }

    /**
     * @param project
     * @param classInfo
     * @throws Exception
     * @author HXH
     * @description: 生成dao代码
     * @date 2024/8/15
     */
    public void generationDaoClass(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationDaoMethod = crudObject.getClass().getDeclaredMethod(GENERATION_DAO_METHOD, Project.class, ClassInfo.class);
        generationDaoMethod.invoke(crudObject, project, classInfo);
    }

    /**
     * @param project
     * @param classInfo
     * @throws Exception
     * @author HXH
     * @description: 生成mapper代码
     * @date 2024/8/15
     */
    public void generationMapper(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationMapperMethod = crudObject.getClass().getDeclaredMethod(GENERATION_MAPPER_METHOD, Project.class, ClassInfo.class);
        generationMapperMethod.invoke(crudObject, project, classInfo);
    }

    /**
     * @param project
     * @param classInfo
     * @throws Exception
     * @author HXH
     * @description: 生成entity代码
     * @date 2024/8/15
     */
    public void generationEntity(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationEntityMethod = crudObject.getClass().getDeclaredMethod(GENERATION_ENTITY_METHOD, Project.class, ClassInfo.class);
        generationEntityMethod.invoke(crudObject, project, classInfo);
    }

    public void generationEntityMappingClass(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> crudClass = Class.forName(myTemplate.getGenCrud());
        Object crudObject = crudClass.newInstance();
        Method generationEntityMethod = crudObject.getClass().getDeclaredMethod(GENERATION_ENTITY_MAPPING_METHOD, Project.class, ClassInfo.class);
        generationEntityMethod.invoke(crudObject, project, classInfo);
    }

    /**
     * @param project
     * @param initExtendTable 初始化除了模板内置表的代码外，是否要初始化用户自己创建表的代码
     * @throws Exception
     * @author HXH
     * @description: 初始化项目
     * @date 2024/8/15
     */
    public void initProject(Project project, boolean initExtendTable) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        Class<?> initProjectClass = Class.forName(myTemplate.getInitBaseProject());
        Object initProjectObject = initProjectClass.newInstance();
        Method initCoreMethod = initProjectObject.getClass().getSuperclass().getDeclaredMethod(INIT_CORE, Project.class, Boolean.class);
        initCoreMethod.invoke(initProjectObject, project, initExtendTable);
    }

    /**
     * @param project
     * @param classInfo
     * @throws Exception
     * @description: 根据表，初始化菜单以及增删查改权限
     * @author HXH
     */
    public void initTableMenu(Project project, ClassInfo classInfo) throws Exception {
        String template = project.getTemplate();
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        String initTableMenu = myTemplate.getInitTableMenu();
        if (StringUtils.isBlank(initTableMenu)) {
            throw new RuntimeException(template + "模板不支持菜单生成！");
        }
        Class<?> initTableMenuClass = Class.forName(initTableMenu);
        Object initTableMenuObject = initTableMenuClass.newInstance();
        Method initTableMenuMethod = initTableMenuObject.getClass().
                getDeclaredMethod(INIT_TABLE_MENU, Project.class, ClassInfo.class);
        initTableMenuMethod.invoke(initTableMenuObject, project, classInfo);
    }

    /**
     * @param project
     * @param classInfo
     * @param className  自定义类名
     * @param methodName 自定义方法名
     * @throws Exception
     * @description: 处理扩展表方法， 参数固定为Project,ClassInfo
     * TemplateConfig中，additionTableMethod字段保存为json数组，格式为：
     * {methodClass:调用类,methodName:调用方法名, showBtn：前端按钮名称, desc:介绍}
     */
    public void processAdditionTableMethod(Project project, ClassInfo classInfo,
                                           String className, String methodName) throws Exception {
        Class<?> additionTableMethodClass = Class.forName(className);
        Object additionTableMethodObject = additionTableMethodClass.newInstance();
        Method additionTableMethod = additionTableMethodObject.getClass().
                getDeclaredMethod(methodName, Project.class, ClassInfo.class);
        additionTableMethod.invoke(additionTableMethodObject, project, classInfo);
    }

    /**
     * @param template
     * @param packageName
     * @param classInfo
     * @return
     * @throws Exception
     * @description: 生成crud工具代码，用于预览代码
     */
    public JSONArray generationCRUDTools(String template, String packageName, ClassInfo classInfo) throws Exception {
        TemplateConfig myTemplate = templateConfigService.getTemplateConfigByName(template);
        String genCrudTools = myTemplate.getCrudTool();
        if (StringUtils.isBlank(genCrudTools)) {
            throw new RuntimeException(template + "模板不支持crud工具生成！");
        }
        Class<?> crudClass = Class.forName(genCrudTools);
        Object crudObject = crudClass.newInstance();
        Method generationCRUDToolsMethod = crudObject.getClass().getDeclaredMethod(PROCESS, String.class, ClassInfo.class, TemplateConfig.class);
        return (JSONArray) generationCRUDToolsMethod.invoke(crudObject, packageName, classInfo, myTemplate);
    }

}
